package comm

import (
	"context"
	"fmt"
	"service/api/api"
	model "service/model/crm_order"
	mCache "service/model/hr_cache"
	mPermis "service/model/permis"
	"strconv"
	"strings"
	"time"

	gpb "gitee.com/cloudapex/protos/crm_order/pb"
	gpa "gitee.com/cloudapex/protos/hr_cache/pb"

	"service/model/mod"

	"gitee.com/cloudapex/ulern/htp"
	"gitee.com/cloudapex/ulern/util"
	"github.com/360EntSecGroup-Skylar/excelize/v2"
	"github.com/gin-gonic/gin"
)

// 订单列表公共入参表
type CommOrderInParam struct {
	CsId      int64          `form:"csId" json:"csId" binding:"omitempty"`         // 客户Id
	OrderId   string         `form:"orderId" json:"orderId" binding:"omitempty"`   // 订单号
	Phone     string         `form:"phone" json:"phone" binding:"omitempty"`       // 手机号
	PriceBgn  int64          `form:"priceBgn" json:"priceBgn" binding:"omitempty"` // 下单金额Bgn
	PriceEnd  int64          `form:"priceEnd" json:"priceEnd" binding:"omitempty"` // 下单金额End
	ProjId    int64          `form:"projId" json:"projId" binding:"omitempty"`     // 项目Id
	OrderType mod.EOrderType `form:"orderTyp" json:"orderTyp" binding:"omitempty"` // 订单类型
	PayType   mod.EPayType   `form:"payTyp" json:"payTyp" binding:"omitempty"`     // 支付类型
	PayTypes  string         `form:"payTyps" json:"payTyps" binding:"omitempty"`   //支付类型
	Refund    int            `form:"refund" json:"refund" binding:"omitempty"`     // 是否退费(0:全部 1:否,2:是)

	OrderBgn int64 `form:"orderBgn" json:"orderBgn" binding:"omitempty"` // 下单时间(int)
	OrderEnd int64 `form:"orderEnd" json:"orderEnd" binding:"omitempty"` // 下单时间(int)
	PayBgn   int64 `form:"payBgn" json:"payBgn" binding:"omitempty"`     // 支付时间(int)
	PayEnd   int64 `form:"payEnd" json:"payEnd" binding:"omitempty"`     // 支付时间(int)
}

// 订单列表公共出参表
type CommOrderOutParam struct {
	Id          int64           `json:"orderId"`    // 订单ID(主键)
	CoId        int64           `json:"commpId"`    // 公司ID
	CustomerId  int64           `json:"customerId"` // 客户ID
	Phone       string          `json:"phone"`      // 手机号
	BillNo      string          `json:"billNo"`     // 订单号
	BillType    mod.EPayType    `json:"billType"`   // 支付类型
	PayType     mod.EPayWay     `json:"payType"`    // 支付方式
	OrderType   mod.EOrderType  `json:"orderType"`  // 订单类型
	UserId      int64           `json:"userId"`     // 成单坐席
	UserName    string          `json:"userName"`   // 成单坐席_
	TeachId     int64           `json:"teachId"`    // 班主任
	TeachName   string          `json:"teachName"`  // 班主任_
	ShowId      uint64          `json:"showId"`     // 所属组织ID
	ShowIdStr   string          `json:"showIdStr"`  // 所属组织ID string
	ShowName    string          `json:"showName"`   // 所属组织ID_
	TotalPrice  int64           `json:"totalPrice"` // 实际支付价格
	CreatedAt   int64           `json:"createdAt"`  // 订单下单时间
	PayAt       int64           `json:"payAt"`      // 订单支付时间
	Notes       string          `json:"notes"`      // 订单通用备注
	Status      mod.EOrderState `json:"status"`     // 订单状态
	CancelAt    int64           `json:"cancelAt"`   // 订单取消时间
	RejectAt    int64           `json:"reasonAt"`   // 订单驳回时间
	RejectCause string          `json:"reason"`     // 订单驳回原因
}

/*
 * 描述: 订单列表(业务端)
 * 路由: /comm/orderBList
 * 方法: GET
 *********************************************************************/
type OrderBList struct {
	mod.SortFinder // 1:下单金额 2:下单时间 3:支付时间
	mod.PageFinder

	CommOrderInParam // 公共参数(见上面结构)

	Who    int32  `form:"who" json:"who" binding:"omitempty,min=0,max=1"` // 0:查自己(默认的) 1:查所有人
	States string `form:"states" json:"states" binding:"omitempty"`       // 订单状态
}
type orderBRspItem struct {
	CommOrderOutParam // 公共参数(见上面结构)

	Details []*model.CrmOrderInfo `json:"details"` // 订单下的网课详情
}

func (this *OrderBList) Handle(c *gin.Context, ctx context.Context) htp.Response {
	user := mod.CurrUser(c)

	userId := user.UId
	util.Cast(this.Who > 0, func() { userId = 0 }, nil)
	states := []int64{}
	for _, it := range strings.Split(this.States, ",") {
		states = append(states, int64(util.ConvInt(it)))
	}
	rsp, err := model.Order.CrmOrderList(ctx, &gpb.CrmOrderListReq{
		Page:       int64(this.PageFinder.Page),
		Count:      int64(this.PageFinder.Pnum),
		Order:      int64(this.SortFinder.Order),
		Orule:      int64(this.SortFinder.Orule + 1),
		CommpId:    user.CId,
		UserId:     userId,
		CustomerId: uint64(this.CsId),
		BillNo:     this.OrderId,
		Phone:      this.Phone,
		PriceBgn:   this.PriceBgn,
		PriceEnd:   this.PriceEnd,
		ProjectId:  this.ProjId,
		OrderType:  int64(this.OrderType),
		BillType:   int64(this.PayType),
		ReFund:     int64(this.Refund),
		OrderBgn:   this.OrderBgn,
		OrderEnd:   this.OrderEnd,
		PayBgn:     this.PayBgn,
		PayEnd:     this.PayEnd,
		State:      states,
		ShowId:     user.ShowId,
	})
	if err != nil {
		return htp.RespModelErr("_o", err)
	}

	items := []*orderBRspItem{}
	if err := util.Convert(&items, rsp.Data); err != nil {
		return htp.RespConvertErr("", err)
	}
	if resp := this.HandleUserNames(c, ctx, items); resp.Err() != nil {
		return resp
	}

	for _, item := range items {
		item.ShowIdStr = fmt.Sprintf("%d", item.ShowId)
	}

	return htp.RespOK("", &struct {
		Total int64       `json:"total"`
		List  interface{} `json:"list"`
	}{rsp.Pager.Total, items})
}
func (this *OrderBList) HandleUserNames(c *gin.Context, ctx context.Context, items []*orderBRspItem) htp.Response {
	if len(items) == 0 {
		return htp.RespOK("", nil)
	}

	user := mod.CurrUser(c)

	uIds := []int64{}
	for _, it := range items {
		uIds = append(uIds, it.UserId, it.TeachId)
	}
	uIds = util.RemoveDuplicate64(uIds)
	rspNameList, err := mCache.UserCacheServer.UserNameList(ctx, &gpa.UserLoginReqIdsReq{CId: user.CId, Ids: uIds})
	if err != nil {
		return htp.RespModelErr("_u", err)
	}
	for _, it := range items {
		flag := 0
		for _, na := range rspNameList.NameList {
			if it.UserId == na.Id {
				flag++
				it.UserName = na.Name
			}
			if it.TeachId == na.Id {
				flag++
				it.TeachName = na.Name
			}
			if flag >= 2 {
				break
			}
		}
	}
	return htp.RespOK("", nil)
}

/*
 * 描述: 订单列表(管理端)
 * 路由: /comm/orderAList
 * 方法: GET
 *********************************************************************/
type OrderAList struct {
	mod.SortFinder // 1:下单金额 2:下单时间 3:支付时间 4:取消时间 5:驳回时间 6:分配时间
	mod.PageFinder

	CommOrderInParam // 公共参数(见上面结构)

	UserId   int64           `form:"userId" json:"userId" binding:"omitempty"`           // 成单坐席
	ShowId   string          `form:"showIdStr" json:"showIdStr" binding:"omitempty"`     // 组织架构Id
	Checked  int             `form:"checked" json:"checked" binding:"omitempty"`         // 订单状态(已审核,优先检测)
	Canceled int             `form:"canceled" json:"canceled" binding:"omitempty"`       // 订单状态(已取消,优先检测)
	State    mod.EOrderState `form:"state" json:"state" binding:"omitempty,min=1,max=6"` // 订单状态(0:默认所有)
	RoleId   int64           `form:"roleId" json:"roleId" binding:"omitempty"`           // 角色(0:全部 1:招生,2:班主任)
	Detailed int32           `form:"detailed" json:"detailed" binding:"omitempty"`       // 导出条件(0:不导出 1:含详情 2:不含详情 3:推广导)(导出时用)

	mapUserRoles map[int64]int32   // 处理用户角色
	mapShowNames map[uint64]string // 处理导出时架构名
}
type orderARspItem struct {
	CommOrderOutParam // 公共参数(见上面结构)

	PlaceId   int64         `json:"placeId"`   // 下单人
	PlaceName string        `json:"placeName"` // 下单人_
	Examine   mod.ECheckWay `json:"examine"`   // 审核方式(1 自动审核 2 手动审核)
	AdminId   int64         `json:"adminId"`   // 审核人
	AdminName string        `json:"adminName"` // 审核人_
	DistrId   int64         `json:"distrId"`   // 分配人
	DistrName string        `json:"distrName"` // 分配人_
	DistrAt   int64         `json:"distrAt"`   // 分配时间

	Details []*model.CrmOrderInfo `json:"details"` // 订单下的网课详情
}

func (this *OrderAList) Handle(c *gin.Context, ctx context.Context) htp.Response {
	user := mod.CurrUser(c)
	this.mapUserRoles = map[int64]int32{}
	this.mapShowNames = map[uint64]string{}

	var payList []int64
	if this.PayTypes != "" {
		plists := strings.Split(this.PayTypes, ",")
		for _, v := range plists {
			v1, _ := strconv.ParseInt(v, 10, 64)
			payList = append(payList, v1)
		}
	}

	fmt.Println(payList)

	pnum, states := this.PageFinder.Pnum, []int64{int64(this.State)}
	util.Cast(this.Detailed != 0, func() { pnum = 10000 }, nil)
	if this.Canceled != 0 {
		states = []int64{}
		states = append(states, int64(mod.EOrderS_HandCancel), int64(mod.EOrderS_AutoCancel))
	} else if this.Checked != 0 {
		states = []int64{}
		states = append(states, int64(mod.EOrderS_Payed), int64(mod.EOrderS_Assign))
	}

	shows := user.ShowId
	util.Cast(this.ShowId != "", func() { shows = []uint64{uint64(util.ConvInt(this.ShowId))} }, nil)

	rsp, err := model.Order.CrmOrderAdminList(ctx, &gpb.CrmOrderListReq{
		Page:        int64(this.PageFinder.Page),
		Count:       int64(pnum),
		Order:       int64(this.SortFinder.Order),
		Orule:       int64(this.SortFinder.Orule + 1),
		CommpId:     user.CId,
		CustomerId:  uint64(this.CsId),
		BillNo:      this.OrderId,
		Phone:       this.Phone,
		PriceBgn:    this.PriceBgn,
		PriceEnd:    this.PriceEnd,
		ProjectId:   this.ProjId,
		OrderType:   int64(this.OrderType),
		BillType:    int64(this.PayType),
		BillTypeArr: payList,
		ReFund:      int64(this.Refund),
		OrderBgn:    this.OrderBgn,
		OrderEnd:    this.OrderEnd,
		PayBgn:      this.PayBgn,
		PayEnd:      this.PayEnd,
		State:       states,
		ShowId:      shows,
		UserId:      this.UserId,
		RoleId:      this.RoleId,
	})
	if err != nil {
		return htp.RespModelErr("_o", err)
	}

	items := []*orderARspItem{}
	if err := util.Convert(&items, rsp.Data); err != nil {
		return htp.RespConvertErr("", err)
	}

	if resp := this.HandleUserNames(c, ctx, items); resp.Err() != nil {
		return resp
	}

	if resp := this.HandleFrameNames(c, ctx, items); resp.Err() != nil {
		return resp
	}

	if this.Detailed != 0 {
		if this.Detailed < 3 {
			return this.HandleExportAD(c, ctx, items) // 行政导出
		} else {
			return this.HandleExportTG(c, ctx, items) // 推广导出
		}
	}
	for _, item := range items {
		item.ShowIdStr = fmt.Sprintf("%d", item.ShowId)
	}
	return htp.RespOK("", &struct {
		Total int64       `json:"total"`
		List  interface{} `json:"list"`
	}{rsp.Pager.Total, items})
}
func (this *OrderAList) HandleUserNames(c *gin.Context, ctx context.Context, items []*orderARspItem) htp.Response {
	user := mod.CurrUser(c)
	if len(items) == 0 {
		return htp.RespOK("", nil)
	}

	uIds := []int64{}
	for _, it := range items {
		uIds = append(uIds, it.UserId, it.TeachId, it.PlaceId, it.AdminId, it.DistrId)
	}
	uIds = util.RemoveDuplicate64(uIds)
	rspNameList, err := mCache.UserCacheServer.UserNameList(ctx, &gpa.UserLoginReqIdsReq{CId: user.CId, Ids: uIds})
	if err != nil {
		return htp.RespModelErr("_u", err)
	}

	mapNames := map[int64]string{}
	for _, it := range rspNameList.NameList {
		mapNames[it.Id] = it.Name
		this.mapUserRoles[it.Id] = int32(it.Role)
	}
	for _, it := range items {
		it.UserName = mapNames[it.UserId]
		it.TeachName = mapNames[it.TeachId]
		it.PlaceName = mapNames[it.PlaceId]
		it.AdminName = mapNames[it.AdminId]
		it.DistrName = mapNames[it.DistrId]
	}
	return htp.RespOK("", nil)
}
func (this *OrderAList) HandleFrameNames(c *gin.Context, ctx context.Context, items []*orderARspItem) htp.Response {
	user := mod.CurrUser(c)
	if len(items) == 0 {
		return htp.RespOK("", nil)
	}

	uShowIds := []uint64{}
	for _, it := range items {
		uShowIds = append(uShowIds, mod.SectionDepartIds(it.ShowId, true)...)
	}
	uShowIds = util.RemoveDuplicateU64(uShowIds)
	rsp, err := mCache.FrameWorkCache.GetFraNameByShowIdList(ctx, &gpa.FullReqUIdsReq{CId: user.CId, Ids: uShowIds})
	if err != nil {
		return htp.RespModelErr("_s", err)
	}

	mapShowNames := map[uint64]string{}
	for _, it := range rsp.FullUList {
		mapShowNames[it.Id] = it.FullName
		this.mapShowNames[it.Id] = it.Name
	}

	for _, it := range items {
		it.ShowName = mapShowNames[it.ShowId]
	}
	return htp.RespOK("", nil)
}
func (this *OrderAList) HandleExportAD(c *gin.Context, ctx context.Context, items []*orderARspItem) htp.Response {
	if len(items) == 0 {
		return htp.RespErr(1, "没有可导出的数据", nil)
	}

	xlsx := excelize.NewFile()
	xlsx.SetSheetRow("Sheet1", "A1", &[]interface{}{
		"客户ID", "订单号", "手机号", "支付类型", "支付方式", "下单金额", "下单时间", "支付时间",
		"所属中心", "所属事业", "所属军团", "所属部门", "所属小组", "成单坐席",
		"订单状态", "订单内容", "学员姓名", "身份证号", "地址", "前端坐席", "审核人", "项目名称",
	})
	for n, it := range items {
		stuName, idCard, address, projName := "", "", "", ""
		if len(it.Details) > 0 {
			stuName = it.Details[0].StudentName
			idCard = it.Details[0].IdCard
			address = it.Details[0].Address
			projName = it.Details[0].ProjectName
		}

		detail := ""
		if this.Detailed == 1 {
			detail = model.DetailsInfo(it.Details)
		}

		dIds := mod.SectionDepartIds(it.ShowId, true)
		xlsx.SetSheetRow("Sheet1", fmt.Sprintf("A%d", n+2), &[]interface{}{
			fmt.Sprintf("%d", it.CustomerId),
			it.BillNo,
			it.Phone,
			it.BillType.String(),
			it.PayType.BString(),
			it.TotalPrice / 100,
			api.TimeFormat(time.Unix(it.CreatedAt, 0)),
			api.TimeFormat(time.Unix(it.PayAt, 0)),
			//it.ShowName, // 所属小组 from showId
			this.mapShowNames[dIds[0]],
			this.mapShowNames[dIds[1]],
			this.mapShowNames[dIds[2]],
			this.mapShowNames[dIds[3]],
			this.mapShowNames[dIds[4]],
			it.UserName, // 成单坐席(班主任)
			it.Status.String(),
			detail,
			stuName,
			idCard,
			address,
			it.PlaceName, // 前端坐席(招生or班主任)
			it.AdminName,
			projName,
		})
	}

	buf, err := xlsx.WriteToBuffer()
	if err != nil {
		return htp.RespErr(2, "导出异常", err)
	}
	return htp.RespFileData(c, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
		fmt.Sprintf("orders_ad[%v].xlsx", util.TimeFormat_(time.Now())), buf.Bytes())
}
func (this *OrderAList) HandleExportTG(c *gin.Context, ctx context.Context, items []*orderARspItem) htp.Response {
	if len(items) == 0 {
		return htp.RespErr(1, "没有可导出的数据", nil)
	}

	xlsx := excelize.NewFile()
	xlsx.SetSheetRow("Sheet1", "A1", &[]interface{}{
		"客户ID", "订单号", "手机号", "支付类型", "支付方式", "下单金额", "下单时间", "支付时间", "成单坐席",
		"所属小组", "坐席类别", "订单类型", "订单状态", "订单内容", "机会来源", "订单渠道", "渠道URL-", "首咨入库时间", "首咨区号", "账户",
	})
	for n, it := range items {
		xlsx.SetSheetRow("Sheet1", fmt.Sprintf("A%d", n+2), &[]interface{}{
			fmt.Sprintf("%d", it.CustomerId),
			it.BillNo,
			it.Phone,
			it.BillType.String(),
			it.PayType.BString(),
			it.TotalPrice / 100,
			api.TimeFormat(time.Unix(it.CreatedAt, 0)),
			api.TimeFormat(time.Unix(it.PayAt, 0)),
			it.UserName, // 成单坐席(班主任)
			it.ShowName, // 所属小组 from showId
			mPermis.RoleName(this.mapUserRoles[it.UserId]),
			it.OrderType.String(),
			it.Status.String(),
			model.DetailsInfo(it.Details),
			"机会来源",
			"订单渠道",
			"渠道URL",
			"首咨入库时间",
			"首咨区号",
			"账户",
		})
	}
	buf, err := xlsx.WriteToBuffer()
	if err != nil {
		return htp.RespErr(2, "导出异常", err)
	}
	return htp.RespFileData(c, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
		fmt.Sprintf("orders_tg[%v].xlsx", util.TimeFormat_(time.Now())), buf.Bytes())
}
